package input

import (
	"fmt"
	"reflect"

	"gitee.com/knowgo/ego/core/function"
)

func parseStruct(typeId string, pool function.ArgumentPool, data interface{}, fn parseFn) (reflect.Value, error) {
	var argType = pool.GetArgumentType(typeId)
	if argType == nil {
		return reflect.ValueOf(nil), fmt.Errorf("cann't find request object")
	}
	if data == nil {
		return reflect.Zero(argType.TypeInfo.ReferenceType), nil
		// return reflect.ValueOf(nil), nil
	}
	info := argType.TypeInfo
	mp, ok := data.(map[string]interface{})
	if !ok {
		return reflect.ValueOf(nil), fmt.Errorf("cann't parse as struct")
	}

	obj := reflect.New(info.ReferenceType).Elem()

	for _, fd := range argType.Fields {
		fieldVal := mp[fd.Name]
		field := obj.FieldByName(fd.FieldName)

		val, err := fn(fd.Name, fieldVal, fd)
		if err != nil {
			return reflect.ValueOf(nil), err
		}
		if fd.TypeInfo.IsPtr || fd.Array || fd.KeyType != "" {
			field.Set(val)
		} else {
			field.Set(reflect.Indirect(val)) // val.Elem())
		}
	}

	obj = obj.Addr()
	for _, v := range argType.Validators {
		if err := v.IsValidate(argType.Name, obj); err != nil {
			return reflect.ValueOf(nil), err
		}
	}

	return obj, nil
}
